package com.qzsoft.zhjd.laboratory.modules.marshallStabilityNew.entity;

import com.qzsoft.zhjd.laboratory.modules.common.ByteUtils;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;

import java.io.Serializable;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;

/**
 *
 * @author MacUncle
 * @since 2025/11/18
 */
@Setter
@Getter
public class BJSSXProtocolParser<R1 extends BJSSXProtocolParser.BaseRealtimeData, R2 extends BJSSXProtocolParser.BaseResultData> {

    // 数据类型 常量
    public static final byte REALTIME_HEX = 0x01; // 数据类型 实时数据[0x01]
    public static final byte RESULT_HEX = 0x02; // 数据类型 实验结果[0x02]

    // 设备类型 常量
    public static final int DEV_MARSHALL = 1; // 1.马歇尔
    public static final int DEV_PENETRATION = 2; // 2.针入度
    public static final int DEV_DUCTILITY = 3; // 3.延度仪
    public static final int DEV_SOFTENING = 4; // 4.软化点

    /**
     * 实验状态 枚举类
     */
    @AllArgsConstructor
    public enum TestStatusEnum implements Serializable {

        /**
         * 0:空闲
         */
        TEST_IDLE(0, "空闲"),

        /**
         * 1:试验中
         */
        TEST_RUNNING(1, "试验中"),

        /**
         * 2:单个试验完成
         */
        TEST_COMPLETE_ONE(2, "单个试验完成"),

        /**
         * 3:一组试验完成
         */
        TEST_COMPLETE_ALL(3, "一组试验完成");

        /**
         * 编码
         */
        private final int code;

        /**
         * 描述
         */
        private final String describe;

        /**
         * 获取描述
         */
        public static String getDesc(int code) {
            return TestStatusEnum.of(code).name();
        }

        /**
         * 快速 构建
         */
        public static TestStatusEnum of(int code) {
            for (TestStatusEnum status : TestStatusEnum.values()) {
                if (status.code == code) {
                    return status;
                }
            }
            return TEST_IDLE; // 默认给定一个 空闲状态！
        }
    }

    /**
     * 实验状态 枚举类
     */
    @AllArgsConstructor
    public enum DeviceTypeEnum implements Serializable {

        /**
         * 0:其他设备
         */
        DEV_OTHER(1, "其他设备"),

        /**
         * 1:马歇尔稳定度
         */
        DEV_MARSHALL(1, "马歇尔稳定度"),

        /**
         * 2:沥青针入度
         */
        DEV_PENETRATION(2, "沥青针入度"),

        /**
         * 3:沥青低温延伸度
         */
        DEV_DUCTILITY(3, "沥青低温延伸度"),

        /**
         * 4:沥青软化点
         */
        DEV_SOFTENING(4, "沥青软化点");

        /**
         * 编码
         */
        private final int code;

        /**
         * 设备名称
         */
        private final String name;

        /**
         * 获取描述
         */
        public static String getDesc(int code) {
            return DeviceTypeEnum.of(code).name();
        }

        /**
         * 快速 构建
         */
        public static DeviceTypeEnum of(int code) {
            for (DeviceTypeEnum status : DeviceTypeEnum.values()) {
                if (status.code == code) {
                    return status;
                }
            }
            return DEV_OTHER;
        }
    }

    /**
     * 数据类型
     *
     * @see #REALTIME_HEX
     * @see #RESULT_HEX
     */
    private byte command;

    /**
     * 数据区长度（不包含类型、长度和 CRC）
     */
    private int length;

    /**
     * 有效值数据
     */
    private byte[] rawData;

    /**
     * 是否为实验结果！
     */
    public boolean isResult() {
        return (this.command == RESULT_HEX);
    }

    /**
     * 实时数据
     * <p>
     * 当 command == {@link #REALTIME_HEX}
     */
    private R1 realtimeData;

    /**
     * 实验结果！
     * <p>
     * 当 command == {@link #RESULT_HEX}
     */
    private R2 resultData;

    /**
     * 响应结果 基本类
     */
    @Setter
    @Getter
    public static abstract class BaseData implements Serializable {

        /**
         * 试样序号
         */
        protected int sampNo;

        /**
         * 设备类型
         * <p>
         * 1.马歇尔 2.针入度 3.延度仪 4.软化点
         *
         * @see #DEV_MARSHALL
         * @see #DEV_PENETRATION
         * @see #DEV_DUCTILITY
         * @see #DEV_SOFTENING
         */
        protected int deviceType;   // 1 马歇尔, 2 针入度, 3 延度, 4 软化点
    }

    /**
     * 解析协议数据帧
     *
     * @param origin 完整的数据帧（类型 + 数据长度 + 数据区 + CRC(16)）
     * @return 解析结果对象（可能是实时数据或四类设备结果）
     */
    public static <R1 extends BJSSXProtocolParser.BaseRealtimeData, R2 extends BJSSXProtocolParser.BaseResultData> BJSSXProtocolParser<R1, R2> parseFrame(byte[] origin, boolean autoParsing) {
        // 最少: 数据类型(1B) + 数据长度(2B)+ 数据1(1B)…数据n(1B)+ CRCH(1B) + CRCL(1B);
        if (origin == null || origin.length < 1 + 2 + 1 + 1) {
            throw new IllegalArgumentException("协议长度太短");
        }

        // TODO：正确的帧格式大小：数据类型(1B) | 数据长度(2B) | 数据1(1B)…数据n(1B) | CRCH(1B) | CRCL(1B);

        // 校验 CRC
        if (!ByteUtils.checkModBusCRC16(origin, 0, origin.length, 2)) {
            throw new IllegalArgumentException("CRC 校验失败");
        }

        byte dataType = origin[0]; // 数据类型 0x01 或 0x02
        int dataLen = ((origin[1] & 0xFF) << 8) | (origin[2] & 0xFF); // 提取数据长度字段

        BJSSXProtocolParser<R1, R2> result = new BJSSXProtocolParser<>();
        result.command = dataType;
        result.length = dataLen;

        // 由 数据长度字段确定
        byte[] realBytes = new byte[dataLen];
        if (dataLen > 0) {
            // 拷贝数据
            System.arraycopy(origin, 1 + 2, realBytes, 0, dataLen);
        }
        result.rawData = realBytes;

        // 确定是否需要自动解析！
        // if (autoParsing) {
        //     // 根据命令分发解析
        //     switch (dataType) {
        //         case REALTIME_HEX: // 实时数据
        //             result.realtimeData = (R1) BaseRealtimeData.parseRealtime(realBytes);
        //             break;
        //         case RESULT_HEX: // 试验结果
        //             result.resultData = (R2) BaseResultData.parseResult(realBytes);
        //             break;
        //         default:
        //             // 未知命令，仅返回 rawData
        //             throw new IllegalArgumentException("未知的数据类型: " + dataType);
        //     }
        // }
        return result;
    }

    /**
     * 实时数据
     * <p>
     * command == 0x01
     *
     * @author MacUncle
     * @since 2025/11/18
     */
    @Getter
    @Setter
    public abstract static class BaseRealtimeData<T extends BaseRealtimeData<T>> extends BaseData {

        /**
         * 试验状态
         * <p>
         * （0:空闲 1:试验中 2:单个试验完成 3:一组试验完成）
         */
        protected int state;

        /**
         * 试样数量
         */
        protected int sampNum;

        /**
         * 每种设备的原有实时数据
         * <p>
         * 固定长度 5
         */
        protected float[] rawFData = new float[5];

        /**
         * 解析 实时数据 帧
         *
         * @param frame       数据帧
         * @param deviceClass 设备类型
         * @return {@link BaseRealtimeData }
         */
        public static /*<T extends BaseRealtimeData<T>> BaseRealtimeData<T>*/ BaseRealtimeData parseRealtime(byte[] frame, Integer deviceClass) {
            // <R1 extends BJSSXProtocolParser.BaseRealtimeData> BJSSXProtocolParser<R1>
            if (frame == null || frame.length < 1 + 1 + 1 + 1 + 5 * 4) {
                // 分析可知：整体的数组长度为：24 [memcpy(&buf[3],sRealData.buf,24)]
                throw new IllegalArgumentException("数据内容长度太短");
            }

            // 设备类别
            int deviceType = frame[3] & 0xFF;

            // fData数据含义表：
            //  数据位    |  马歇尔稳定度仪	|    针入度	     |   延度仪	          | 软化点
            // ----------+--------------+----------------+--------------------+--------------
            // fData[0]  |  流值(mm)	    |    针入度1(mm)	 |   试样1拉伸长度(mm)  |	软化点温度1(℃)
            // fData[1]  |  压力(kN)	    |    针入度2(mm)	 |   试样2拉伸长度(mm)  |	软化点温度2(℃)
            // fData[2]  |  保留	        |    针入度3(mm)	 |   试样3拉伸长度(mm)  |	升温速率(℃/min)
            // fData[3]  |  保留	        |    当前温度(℃)	 |   水温(℃)	      | 保留
            // fData[4]  |  保留	        |    保留	     |   保留	          | 保留
            float[] fData = new float[5];
            // 解析字节数组转为 float
            for (int i = 0; i < 5; i++) {
                fData[i] = ByteBuffer.wrap(frame, 4 + i * 4, 4) // float = 4 * byte
                    .order(ByteOrder.LITTLE_ENDIAN) // 分析可知数组为小端序；采用标准的 IEEE 754表示 float 精度！
                    .getFloat();
            }

            if (deviceClass != null) {
                // 强制覆盖 设备类型解析数据！
                deviceType = deviceClass;
            }

            // 根据设备类型解析不同的设备数据
            switch (deviceType) {
                case DEV_MARSHALL:
                    MarshallStabilityRealtimeData marshallStability = new MarshallStabilityRealtimeData();
                    // 前四个字节一致，统一设定即可！
                    marshallStability.state = frame[0] & 0xFF;
                    marshallStability.sampNum = frame[1] & 0xFF;
                    marshallStability.sampNo = frame[2] & 0xFF;
                    marshallStability.deviceType = deviceType;
                    marshallStability.rawFData = fData;

                    // 独有数据
                    marshallStability.flow = fData[0];
                    marshallStability.stability = fData[1];

                    // realtimeData = marshallStability;
                    return marshallStability;
                case DEV_PENETRATION:
                    PenetrationRealtimeData penetration = new PenetrationRealtimeData();
                    // 前四个字节一致，统一设定即可！
                    penetration.state = frame[0] & 0xFF;
                    penetration.sampNum = frame[1] & 0xFF;
                    penetration.sampNo = frame[2] & 0xFF;
                    penetration.deviceType = deviceType;
                    penetration.rawFData = fData;

                    // 独有数据
                    penetration.penetration1 = fData[0];
                    penetration.penetration2 = fData[1];
                    penetration.penetration3 = fData[2];
                    penetration.currentTemp = fData[3];

                    return penetration;
                case DEV_DUCTILITY:
                    DuctilityRealtimeData ductility = new DuctilityRealtimeData();
                    // 前四个字节一致，统一设定即可！
                    ductility.state = frame[0] & 0xFF;
                    ductility.sampNum = frame[1] & 0xFF;
                    ductility.sampNo = frame[2] & 0xFF;
                    ductility.deviceType = deviceType;
                    ductility.rawFData = fData;

                    // 独有数据
                    ductility.extension1 = fData[0];
                    ductility.extension2 = fData[1];
                    ductility.extension3 = fData[2];
                    ductility.waterTemp = fData[3];

                    return ductility;
                case DEV_SOFTENING:
                    SofteningPointRealtimeData softeningPoint = new SofteningPointRealtimeData();
                    // 前四个字节一致，统一设定即可！
                    softeningPoint.state = frame[0] & 0xFF;
                    softeningPoint.sampNum = frame[1] & 0xFF;
                    softeningPoint.sampNo = frame[2] & 0xFF;
                    softeningPoint.deviceType = deviceType;
                    softeningPoint.rawFData = fData;

                    // 独有数据
                    softeningPoint.softeningPoint1 = fData[0];
                    softeningPoint.softeningPoint2 = fData[1];
                    softeningPoint.heatingRate = fData[2];

                    return softeningPoint;
                default:
                    // 未知命令，仅返回 rawData
                    throw new IllegalArgumentException("未知的设备类型: " + deviceType);
            }

            // return realtimeData;
        }
    }

    /**
     * 马歇尔稳定度
     * <p>
     * 实时数据
     * <p>
     * 说明：一次只能做一个试样，每个试样完成时都会发生试验结果，当试样序号+1≥试样数量时，一组试验完成；
     *
     * @see #DEV_MARSHALL
     * @see #REALTIME_HEX
     */
    @Getter
    @Setter
    public static class MarshallStabilityRealtimeData extends BaseRealtimeData<MarshallStabilityRealtimeData> {

        /**
         * 流值 (mm)
         */
        protected float flow;

        /**
         * 稳定度 (kN)
         */
        protected float stability;

        @Override
        public String toString() {
            return "马歇尔稳定度: \n" +
                   String.format("设备类型: %s\n 试样序号: %d\n 试样状态: %s\n 试样数量: %d\n", DeviceTypeEnum.getDesc(deviceType), sampNo, TestStatusEnum.getDesc(state), sampNum) +
                   String.format("流值(mm): %fg\n, 稳定度(kN): %fg", flow, stability);
        }
    }

    /**
     * 针入度
     * <p>
     * 实时数据
     * <p>
     * 说明：一次只能做一个试样，每个试样完成时都会发生试验结果，当试样序号+1≥试样数量时，一组试验完成；
     *
     * @see #DEV_PENETRATION
     * @see #REALTIME_HEX
     */
    @Getter
    @Setter
    public static class PenetrationRealtimeData extends BaseRealtimeData<PenetrationRealtimeData> {

        /**
         * 当前温度(℃)
         * <p>
         * 未确定是否小数
         */
        protected float currentTemp;

        // ****** 是单独分开？还是放到list集合中？  ***** //

        /**
         * 针入度①(mm)
         */
        protected float penetration1;

        /**
         * 针入度②(mm)
         */
        protected float penetration2;

        /**
         * 针入度③(mm)
         */
        protected float penetration3;

        @Override
        public String toString() {
            return "沥青针入度: \n" +
                   String.format("设备类型: %s\n 试样序号: %d\n 试样状态: %s\n 试样数量: %d\n", DeviceTypeEnum.getDesc(deviceType), sampNo, TestStatusEnum.getDesc(state), sampNum) +
                   String.format("当前温度(℃): %fg\n, 针入度①(mm): %fg, 针入度②(mm): %fg, 针入度③(mm): %fg", currentTemp, penetration1, penetration2, penetration3);
        }

    }

    /**
     * 延度仪
     * <p>
     * 实时数据
     * <p>
     * 说明：延度仪3个试样一起试验，全部结束时发送一次结果；
     *
     * @see #DEV_DUCTILITY
     * @see #REALTIME_HEX
     */
    @Getter
    @Setter
    public static class DuctilityRealtimeData extends BaseRealtimeData<DuctilityRealtimeData> {

        /**
         * 水温(℃)
         */
        protected float waterTemp;

        // ****** 是单独分开？还是放到list集合中？  ***** //

        /**
         * 试样①拉伸长度(mm)
         */
        protected float extension1;

        /**
         * 试样②拉伸长度(mm)
         */
        protected float extension2;

        /**
         * 试样③拉伸长度(mm)
         */
        protected float extension3;

        @Override
        public String toString() {
            return "沥青低温延伸度: \n" +
                   String.format("设备类型: %s\n 试样序号: %d\n 试样状态: %s\n 试样数量: %d\n", DeviceTypeEnum.getDesc(deviceType), sampNo, TestStatusEnum.getDesc(state), sampNum) +
                   String.format("水温(℃): %fg\n, 试样①拉伸长度(mm): %fg, 试样②拉伸长度(mm): %fg, 试样③拉伸长度(mm): %fg", waterTemp, extension1, extension2, extension3);
        }

    }

    /**
     * 软化点
     * <p>
     * 实时数据
     * <p>
     * 说明：软化点2个试样一起试验，全部结束时发送一次结果；
     *
     * @see #DEV_SOFTENING
     * @see #REALTIME_HEX
     */
    @Getter
    @Setter
    public static class SofteningPointRealtimeData extends BaseRealtimeData<SofteningPointRealtimeData> {

        /**
         * 升温速率(℃/min)
         */
        protected float heatingRate;

        // ****** 是单独分开？还是放到list集合中？  ***** //

        /**
         * 软化点①温度(℃)
         */
        protected float softeningPoint1;

        /**
         * 软化点②温度(℃)
         */
        protected float softeningPoint2;

        @Override
        public String toString() {
            return "沥青软化点: \n" +
                   String.format("设备类型: %s\n 试样序号: %d\n 试样状态: %s\n 试样数量: %d\n", DeviceTypeEnum.getDesc(deviceType), sampNo, TestStatusEnum.getDesc(state), sampNum) +
                   String.format("升温速率(℃/min): %fg\n, 软化点①温度(℃): %fg, 软化点②温度(℃): %fg", heatingRate, softeningPoint1, softeningPoint2);
        }

    }


    /**
     * 结果数据
     * <p>
     * command == 0x02
     *
     * @author MacUncle
     * @since 2025/11/18
     */
    @Setter
    @Getter
    public static abstract class BaseResultData extends BaseData {

        /**
         * 每种设备的原有实时数据
         * <p>
         * 马歇尔稳定度为20，其他设备为5;
         */
        protected float[] rawFRlt = new float[20];

        /**
         * 解析 结果数据 帧
         *
         * @param frame 数据帧
         * @return {@link BaseResultData }
         */
        public static BaseResultData parseResult(byte[] frame) {

            if (frame == null || frame.length < 1 + 1 + 1 + 1 + 5 * 4) {
                // 分析可知：非马歇尔稳定剂设备外整体的数组长度为：24 [memcpy(&buf[3],sResult.buf,24)]
                throw new IllegalArgumentException("数据内容长度太短");
            }

            // 设备类别
            int deviceType = frame[3] & 0xFF;
            int dataLen = 0; // 数据长度，其中'马歇尔稳定度仪'为 20；其他为 5！

            if (DEV_MARSHALL == deviceType) {
                // 马歇尔稳定度
                if (frame.length < 1 + 1 + 1 + 1 + 20 * 4) {
                    // 马歇尔稳定度数组长度84才对
                    throw new IllegalArgumentException("数据内容长度太短");
                }
                dataLen = 20;
            } else {
                dataLen = 5;
            }

            // BaseResultData resultData = new BaseResultData() {
            // };

            // fData数据含义表：
            //  数据位    |  马歇尔稳定度仪	|    针入度	     |   延度仪	          | 软化点
            // ----------+--------------+----------------+--------------------+--------------
            // fRlt[0]  |  流值1(mm)	    |    针入度1(mm)	 |   试样1拉伸长度(mm)  |	软化点温度1(℃)
            // fRlt[1]  |  稳定度1(kN)	|    针入度2(mm)	 |   试样2拉伸长度(mm)  |	软化点温度2(℃)
            // fRlt[2]  |  流值2(mm)	    |    针入度3(mm)	 |   试样3拉伸长度(mm)  |	升温速率(℃/min)
            // fRlt[3]  |  稳定度2(kN)	|    当前温度(℃)	 |   水温(℃)	      | 保留
            // fRlt[4]  |  流值3(mm)	    |    保留	     |   保留	          | 保留
            // fRlt[5]  |  稳定度3(kN)	|    保留	     |   保留	          | 保留
            // fRlt[6]  |  流值4(mm)	    |    保留	     |   保留	          | 保留
            // fRlt[7]  |  稳定度4(kN)	|    保留	     |   保留	          | 保留
            // fRlt[8]  |  流值5(mm)	    |    保留	     |   保留	          | 保留
            // fRlt[9]  |  稳定度5(kN)	|    保留	     |   保留	          | 保留
            // fRlt[10]  |  流值6(mm)	 |    保留	     |   保留	          | 保留
            // fRlt[11]  |  稳定度6(kN)	 |    保留	     |   保留	          | 保留
            // fRlt[12]  |  流值7(mm)	 |    保留	     |   保留	          | 保留
            // fRlt[13]  |  稳定度7(kN)	 |    保留	     |   保留	          | 保留
            // fRlt[14]  |  流值8(mm)	 |    保留	     |   保留	          | 保留
            // fRlt[15]  |  稳定度8(kN)	 |    保留	     |   保留	          | 保留
            // fRlt[16]  |  流值9(mm)	 |    保留	     |   保留	          | 保留
            // fRlt[17]  |  稳定度9(kN)	 |    保留	     |   保留	          | 保留
            // fRlt[18]  |  流值10(mm)	 |    保留	     |   保留	          | 保留
            // fRlt[19]  |  稳定度10(kN)	 |    保留	     |   保留	          | 保留

            float[] fRlt = new float[dataLen];
            // 解析字节数组转为 float
            for (int i = 0; i < dataLen; i++) {
                fRlt[i] = ByteBuffer.wrap(frame, 4 + i * 4, 4) // float = 4 * byte
                    .order(ByteOrder.LITTLE_ENDIAN) // 分析可知数组为小端序；采用标准的 IEEE 754表示 float 精度！
                    .getFloat();
            }

            // 根据设备类型解析不同的设备数据
            switch (deviceType) {
                // fRlt数据含义表：
                //  数据位    |   马歇尔稳定度仪	| 针入度	   | 延度仪	  |  软化点
                // ----------+------------------+----------+----------+----------
                // byData1	 |   试样序号	    | 试样序号	   | 试样序号	|    试样序号
                // byData2	 |   试样数量	    | 设定温度	   | 设定温度	|    设定升温速率
                // byData3	 |   试验状态(0:空闲 1: 2:单个试验完成 3:一组试验完成)	| 保留	| 拉伸速度	| 保留
                // byData4	 |   设备类型	    | 设备类型	   | 设备类型	|    设备类型
                case DEV_MARSHALL:

                    MarshallStabilityResultData marshallStability = new MarshallStabilityResultData();
                    marshallStability.state = frame[2] & 0xFF;
                    marshallStability.sampNum = frame[1] & 0xFF;
                    marshallStability.sampNo = frame[0] & 0xFF;
                    marshallStability.deviceType = deviceType;

                    marshallStability.rawFRlt = fRlt;

                    // 独有数据

                    // ****** 放到list集合中是不是更优雅？？  ***** //
                    marshallStability.stability10 = fRlt[dataLen--];
                    marshallStability.flow10 = fRlt[dataLen--];
                    marshallStability.stability9 = fRlt[dataLen--];
                    marshallStability.flow9 = fRlt[dataLen--];
                    marshallStability.stability8 = fRlt[dataLen--];
                    marshallStability.flow8 = fRlt[dataLen--];
                    marshallStability.stability7 = fRlt[dataLen--];
                    marshallStability.flow7 = fRlt[dataLen--];
                    marshallStability.stability6 = fRlt[dataLen--];
                    marshallStability.flow6 = fRlt[dataLen--];
                    marshallStability.stability5 = fRlt[dataLen--];
                    marshallStability.flow5 = fRlt[dataLen--];
                    marshallStability.stability4 = fRlt[dataLen--];
                    marshallStability.flow4 = fRlt[dataLen--];
                    marshallStability.stability3 = fRlt[dataLen--];
                    marshallStability.flow3 = fRlt[dataLen--];
                    marshallStability.stability2 = fRlt[dataLen--];
                    marshallStability.flow2 = fRlt[dataLen--];
                    marshallStability.stability1 = fRlt[dataLen--];
                    marshallStability.flow1 = fRlt[dataLen];

                    return marshallStability;
                case DEV_PENETRATION:
                    PenetrationResultData penetration = new PenetrationResultData();
                    penetration.sampNo = frame[0] & 0xFF;
                    penetration.presetTemp = frame[1] & 0xFF;
                    penetration.other1 = frame[2] & 0xFF;
                    penetration.deviceType = deviceType;

                    penetration.rawFRlt = fRlt;

                    // 独有数据
                    penetration.penetration1 = fRlt[0];
                    penetration.penetration2 = fRlt[1];
                    penetration.penetration3 = fRlt[2];

                    return penetration;
                case DEV_DUCTILITY:
                    DuctilityResultData ductility = new DuctilityResultData();
                    ductility.sampNo = frame[0] & 0xFF;
                    ductility.presetTemp = frame[1] & 0xFF;
                    ductility.stretchRate = frame[2] & 0xFF;
                    ductility.deviceType = deviceType;

                    ductility.rawFRlt = fRlt;

                    // 独有数据
                    ductility.extension1 = fRlt[0];
                    ductility.extension2 = fRlt[1];
                    ductility.extension3 = fRlt[2];

                    return ductility;
                case DEV_SOFTENING:
                    SofteningPointResultData softeningPoint = new SofteningPointResultData();
                    softeningPoint.sampNo = frame[0] & 0xFF;
                    softeningPoint.heatingRate = frame[1] & 0xFF;
                    softeningPoint.other1 = frame[2] & 0xFF;
                    softeningPoint.other2 = frame[3] & 0xFF;
                    softeningPoint.deviceType = deviceType;

                    softeningPoint.rawFRlt = fRlt;

                    // 独有数据
                    softeningPoint.softeningPoint1 = fRlt[0];
                    softeningPoint.softeningPoint2 = fRlt[1];

                    return softeningPoint;
                default:
                    // 未知命令，仅返回 rawData
                    throw new IllegalArgumentException("未知的设备类型: " + deviceType);
            }

            // return resultData;
        }
    }

    /**
     * 马歇尔稳定度
     * <p>
     * 实验结果
     * <p>
     * 说明：一次只能做一个试样，每个试样完成时都会发生试验结果，当试样序号+1≥试样数量时，一组试验完成；
     *
     * @see #DEV_MARSHALL
     * @see #RESULT_HEX
     */
    @Getter
    @Setter
    public static class MarshallStabilityResultData extends BaseResultData {

        /**
         * 试样数量
         */
        protected int sampNum;

        /**
         * 试验状态
         * <p>
         * （0:空闲 1:试验中 2:单个试验完成 3:一组试验完成）
         */
        protected int state;

        // ****** 是单独分开？还是放到list集合中？  ***** //

        /**
         * 流值1 (mm)
         */
        protected float flow1;

        /**
         * 稳定度1 (kN)
         */
        protected float stability1;

        /**
         * 流值2 (mm)
         */
        protected float flow2;

        /**
         * 稳定度2 (kN)
         */
        protected float stability2;

        /**
         * 流值3 (mm)
         */
        protected float flow3;

        /**
         * 稳定度3 (kN)
         */
        protected float stability3;

        /**
         * 流值4 (mm)
         */
        protected float flow4;

        /**
         * 稳定度4 (kN)
         */
        protected float stability4;

        /**
         * 流值5 (mm)
         */
        protected float flow5;

        /**
         * 稳定度5 (kN)
         */
        protected float stability5;

        /**
         * 流值6 (mm)
         */
        protected float flow6;

        /**
         * 稳定度6 (kN)
         */
        protected float stability6;

        /**
         * 流值7 (mm)
         */
        protected float flow7;

        /**
         * 稳定度7 (kN)
         */
        protected float stability7;

        /**
         * 流值8 (mm)
         */
        protected float flow8;

        /**
         * 稳定度8 (kN)
         */
        protected float stability8;

        /**
         * 流值9 (mm)
         */
        protected float flow9;

        /**
         * 稳定度9 (kN)
         */
        protected float stability9;

        /**
         * 流值10 (mm)
         */
        protected float flow10;

        /**
         * 稳定度10 (kN)
         */
        protected float stability10;

        @Override
        public String toString() {
            return "马歇尔稳定度: \n" +
                   String.format("设备类型: %s\n 试样序号: %d\n 试样状态: %s\n 试样数量: %d\n", DeviceTypeEnum.getDesc(deviceType), sampNo, TestStatusEnum.getDesc(state), sampNum) +
                   String.format("流值1(mm): %fg\n, 稳定度1(kN): %fg", flow1, stability1) +
                   String.format("流值2(mm): %fg\n, 稳定度2(kN): %fg", flow2, stability2) +
                   String.format("流值3(mm): %fg\n, 稳定度3(kN): %fg", flow3, stability3) +
                   String.format("流值4(mm): %fg\n, 稳定度4(kN): %fg", flow4, stability4) +
                   String.format("流值5(mm): %fg\n, 稳定度5(kN): %fg", flow5, stability5) +
                   String.format("流值6(mm): %fg\n, 稳定度6(kN): %fg", flow6, stability6) +
                   String.format("流值7(mm): %fg\n, 稳定度7(kN): %fg", flow7, stability7) +
                   String.format("流值8(mm): %fg\n, 稳定度8(kN): %fg", flow8, stability8) +
                   String.format("流值9(mm): %fg\n, 稳定度9(kN): %fg", flow9, stability9) +
                   String.format("流值10(mm): %fg\n, 稳定度10(kN): %fg", flow10, stability10);
        }
    }

    /**
     * 针入度
     * <p>
     * 实验结果
     * <p>
     * 说明：一次只能做一个试样，每个试样完成时都会发生试验结果，当试样序号+1≥试样数量时，一组试验完成；
     *
     * @see #DEV_PENETRATION
     * @see #RESULT_HEX
     */
    @Getter
    @Setter
    public static class PenetrationResultData extends BaseResultData {

        /**
         * 设定温度(℃)
         * <p>
         * 未确定是否为小数
         */
        protected int presetTemp;

        /**
         * 保留字段（无法确定意义）
         */
        @Deprecated
        protected int other1;

        // ****** 是单独分开？还是放到list集合中？  ***** //

        /**
         * 针入度①(mm)
         */
        protected float penetration1;

        /**
         * 针入度②(mm)
         */
        protected float penetration2;

        /**
         * 针入度③(mm)
         */
        protected float penetration3;

        @Override
        public String toString() {
            return "沥青针入度: \n" +
                   String.format("设备类型: %s\n 试样序号: %d\n 设定温度(℃): %d\n", DeviceTypeEnum.getDesc(deviceType), sampNo, presetTemp) +
                   String.format("设定温度(℃): %dg\n, 针入度①(mm): %fg, 针入度②(mm): %fg, 针入度③(mm): %fg", presetTemp, penetration1, penetration2, penetration3);
        }

    }

    /**
     * 延度仪
     * <p>
     * 实验结果
     * <p>
     * 说明：延度仪3个试样一起试验，全部结束时发送一次结果；
     *
     * @see #DEV_DUCTILITY
     * @see #RESULT_HEX
     */
    @Getter
    @Setter
    public static class DuctilityResultData extends BaseResultData {

        /**
         * 设定温度(℃)
         * <p>
         * 未确定是否为小数
         */
        protected int presetTemp;

        /**
         * 拉伸速度(mm/min)
         * <p>
         * 暂未确定单位！
         */
        protected int stretchRate;

        // ****** 是单独分开？还是放到list集合中？  ***** //

        /**
         * 试样①拉伸长度(mm)
         */
        protected float extension1;

        /**
         * 试样②拉伸长度(mm)
         */
        protected float extension2;

        /**
         * 试样③拉伸长度(mm)
         */
        protected float extension3;

        @Override
        public String toString() {
            return "沥青低温延伸度: \n" +
                   String.format("设备类型: %s\n 试样序号: %d\n 设定温度(℃): %d\n 拉伸速度(mm/min): %d\n", DeviceTypeEnum.getDesc(deviceType), sampNo, presetTemp, stretchRate) +
                   String.format("设定温度(℃): %dg\n, 试样①拉伸长度(mm): %fg, 试样②拉伸长度(mm): %fg, 试样③拉伸长度(mm): %fg", presetTemp, extension1, extension2, extension3);
        }

    }

    /**
     * 软化点
     * <p>
     * 实验结果
     * <p>
     * 说明： 软化点2个试样一起试验，全部结束时发送一次结果；
     *
     * @see #DEV_SOFTENING
     * @see #RESULT_HEX
     */
    @Getter
    @Setter
    public static class SofteningPointResultData extends BaseResultData {

        /**
         * 设定升温速率(℃/min)
         */
        protected float heatingRate;

        /**
         * 保留字段（无法确定意义）
         */
        @Deprecated
        protected int other1;

        /**
         * 保留字段（无法确定意义）
         */
        @Deprecated
        protected int other2;


        /**
         * 试样①软化点温度(℃)
         */
        protected float softeningPoint1;

        /**
         * 试样②软化点温度(℃)
         */
        protected float softeningPoint2;

        @Override
        public String toString() {
            return "沥青软化点: \n" +
                   String.format("设备类型: %s\n 试样序号: %d\n 设定升温速率(℃/min): %fg\n ", DeviceTypeEnum.getDesc(deviceType), sampNo, heatingRate) +
                   String.format("升温速率(℃/min): %fg\n, 软化点①温度(℃): %fg, 软化点②温度(℃): %fg", heatingRate, softeningPoint1, softeningPoint2);
        }
    }

}
